#ifndef EMS_PROTOCOL_MODBUS_MODBUS_TCP_H
#define EMS_PROTOCOL_MODBUS_MODBUS_TCP_H

#include "protocol/ProtocolInterface.h"
#include <string>
#include <memory>

typedef struct _modbus modbus_t;

namespace ems {
namespace protocol {

class ModbusTCP : public ProtocolInterface {
public:
    ModbusTCP(const std::string& host, int port);
    virtual ~ModbusTCP();
    
    bool connect() override;
    void disconnect() override;
    bool isConnected() const override;
    
    void setSlaveId(int slaveId);
    void setTimeout(int timeoutMs);
    
    bool readHoldingRegisters(uint16_t address, uint16_t count, std::vector<uint16_t>& data) override;
    bool readInputRegisters(uint16_t address, uint16_t count, std::vector<uint16_t>& data) override;
    bool readCoils(uint16_t address, uint16_t count, std::vector<bool>& data) override;
    bool readDiscreteInputs(uint16_t address, uint16_t count, std::vector<bool>& data) override;
    
    bool writeSingleRegister(uint16_t address, uint16_t value) override;
    bool writeMultipleRegisters(uint16_t address, const std::vector<uint16_t>& values) override;
    bool writeSingleCoil(uint16_t address, bool value) override;
    bool writeMultipleCoils(uint16_t address, const std::vector<bool>& values) override;
    
    std::string getLastError() const override;
    ProtocolType getType() const override { return ProtocolType::MODBUS_TCP; }

private:
    std::string host_;
    int port_;
    int slaveId_;
    int timeout_;
    
    modbus_t* ctx_;
    bool connected_;
    mutable std::string lastError_;
    
    bool ensureConnection();
    void handleConnectionFailure(int errCode, const std::string& action);
    void markDisconnected();
    bool isConnectionError(int errCode) const;
    void updateLastError(int errCode) const;
};

}  // namespace protocol
}  // namespace ems

#endif  // EMS_PROTOCOL_MODBUS_MODBUS_TCP_H
